package org.lex.jdbc.url.view.internal;

import java.awt.event.ActionEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventObject;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.lex.jdbc.DriverLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DriverConfigPaneOper {
	private final DriverConfigPane pane;
	private final FileNameExtensionFilter jarFileFilter = new FileNameExtensionFilter(
			"Java Archive File", "jar");
	private File lastDriverFile = null;
	private Logger log = LoggerFactory.getLogger(DriverConfigPaneOper.class);

	public DriverConfigPaneOper(DriverConfigPane pane) {
		super();
		this.pane = pane;
	}

	// ====================================================
	// classpath action
	// ====================================================
	void addDriverFileAction(ActionEvent e) {
		this.showAddFileDialog(this.lastDriverFile);
	}

	void editDriverFileAction(EventObject e) {
		JList<File> list = pane.getClasspathList();
		List<File> selectedFiles = list.getSelectedValuesList();
		if (null == selectedFiles || true == selectedFiles.isEmpty()) {
			log.error("no file selected for edit");
			JOptionPane.showMessageDialog(pane,
					"Must select a file before 'Edit'", "No file selected",
					JOptionPane.ERROR_MESSAGE);
		} else if (1 != selectedFiles.size()) {
			log.error("more than 1 files selected, can't edit");
			JOptionPane.showMessageDialog(pane,
					"You can only edit a single file",
					"Too many files selected", JOptionPane.ERROR_MESSAGE);
		} else {
			File file = selectedFiles.get(0);
			log.debug("select file to edit: {}", file);
			File[] results = this.showAddFileDialog(file);
			if (null != results && 0 != results.length) {
				pane.getClasspathListModel().removeElement(file);
			}
		}
	}

	void removeDriverFileAction(ActionEvent e) {
		List<File> selectedFiles = pane.getClasspathList()
				.getSelectedValuesList();
		if (null == selectedFiles || true == selectedFiles.isEmpty()) {
			log.info("no driver file selected, nothing to remove");
		} else {
			DefaultListModel<File> model = pane.getClasspathListModel();
			for (File file : selectedFiles) {
				model.removeElement(file);
			}
		}
	}

	void listDriverClassAction(ActionEvent e) {
		DefaultListModel<File> model = pane.getClasspathListModel();
		final List<File> files = new ArrayList<File>(model.getSize());
		for (int i = 0, n = model.getSize(); i < n; i++) {
			files.add(model.get(i));
		}
		log.info("loading driver from {} files: {}", files.size(), files);
		pane.getClassComboBoxModel().removeAllElements();
		new SwingWorker<List<String>, File>() {
			@Override
			protected List<String> doInBackground() throws Exception {
				return new DriverLoader().loadDriverClassNames(files);
			}

			@Override
			protected void done() {
				try {
					List<String> results = this.get();
					log.info("{} driver loaded: {}", results.size(), results);
					DefaultComboBoxModel<String> model = pane
							.getClassComboBoxModel();
					for (String r : results) {
						model.addElement(r);
					}
				} catch (Exception e) {
					log.error("load driver class names failed", e);
				} finally {
					super.done();
				}
			}
		}.execute();
	}

	private File[] showAddFileDialog(File initDir) {
		File[] files = null;

		JFileChooser fc = new JFileChooser();
		fc.setCurrentDirectory(initDir);
		fc.setFileHidingEnabled(false);
		fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		fc.setMultiSelectionEnabled(true);
		fc.setFileFilter(jarFileFilter);
		int returnVal = fc.showOpenDialog(pane);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			files = fc.getSelectedFiles();
			log.debug("selected driver file/dir: {}", Arrays.toString(files));
			if (null != files) {
				for (File file : files) {
					if (null != file) {
						this.lastDriverFile = file;
					}
					if (null != file && file.exists()
							&& (file.isFile() ? file.canRead() : true)) {
						log.trace("add file to driver file list: {}", file);
						this.pane.addDriverFile(file);
					} else {
						log.error("selected file not exists, or not readable");
						JOptionPane.showMessageDialog(pane,
								"Choosen file not exists, or not readable:"
										+ file, "Add Driver Failed",
								JOptionPane.ERROR_MESSAGE);
					}
				}
			}
		}
		return files;
	}
}
